﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace ComputerVision
{
    delegate long IntPtrToBitmapCallback(IntPtr input, Bitmap output);
    delegate long BitmapToBitmapCallback(Bitmap input, Bitmap output);
    class DecodeParameters
    {
        public static readonly int MaxBufferSize = 10;
        public readonly Control Display;
        public readonly Queue<Bitmap> Buffer = new Queue<Bitmap>();
        public Bitmap ImageDecode = null;
        public readonly IntPtrToBitmapCallback YV12DecodeCall = null;
        public readonly BitmapToBitmapCallback BitmapDecodeCall = null;
        public long DecodeSpan { get; private set; }
        public DecodeParameters()
        {

        }

        public DecodeParameters(Control display)
        {
            if (display != null)
            {
                this.Display = display;
                this.Display.Paint += new PaintEventHandler(Display_Paint);
            }
        }

        public DecodeParameters(Control display, IntPtrToBitmapCallback decodeCall)
            : this(display)
        {
            this.YV12DecodeCall = decodeCall;
        }

        public DecodeParameters(Control display, BitmapToBitmapCallback decodeCall)
            : this(display)
        {
            this.BitmapDecodeCall = decodeCall;
        }

        void Display_Paint(object sender, PaintEventArgs e)
        {
            if (this.Display == null || this.ImageDecode == null) return;

            lock (this.ImageDecode)
            {
                e.Graphics.DrawImage(this.ImageDecode, new Rectangle(0, 0, this.Display.Width, this.Display.Height));
            }
        }

        public void DecodeImage(IntPtr input, out Bitmap output, int width, int height)
        {
            Bitmap imageOut = null;
            if (this.Buffer.Count < DecodeParameters.MaxBufferSize
                && this.YV12DecodeCall != null)
            {
                imageOut = new Bitmap(width, height);
                this.DecodeSpan = this.YV12DecodeCall(input, imageOut);
                output = imageOut.Clone() as Bitmap;
                this.Buffer.Enqueue(imageOut);
            }
            else
                output = null;
        }

        public void DecodeImage(Bitmap input, out Bitmap output, int width, int height)
        {
            if (this.Buffer.Count < DecodeParameters.MaxBufferSize
                && this.BitmapDecodeCall != null)
            {
                lock (input)
                {
                    Bitmap imageOut = new Bitmap(width, height);
                    this.DecodeSpan = this.BitmapDecodeCall(input, imageOut);
                    output = imageOut.Clone() as Bitmap;
                    this.Buffer.Enqueue(imageOut);
                }
            }
            else
                output = null;
        }

        public void DecodeImage(Bitmap input, int width, int height)
        {
            if (this.Buffer.Count < DecodeParameters.MaxBufferSize
                && this.BitmapDecodeCall != null)
            {
                lock (input)
                {
                    Bitmap imageOut = new Bitmap(width, height);
                    this.DecodeSpan = this.BitmapDecodeCall(input, imageOut);
                    this.Buffer.Enqueue(imageOut);
                }
            }
        }

        public void ShowImage()
        {
            if (this.Buffer.Count == 0) return;
            if (this.ImageDecode != null)
            {
                lock (this.ImageDecode)
                {
                    this.ImageDecode.Dispose();
                    this.ImageDecode = null;
                }
            }
            this.ImageDecode = this.Buffer.Dequeue();

            if (this.Display != null) this.Display.Invalidate();
        }

    }
}
